from datetime import datetime, timedelta
from ..models import Book, BorrowRecord, User, Reservation, ReturnRequest, Notification
from ..extensions import db
from ..extensions import BookNotAvailableError, NotFoundError
from flask import current_app

class BookService:
    @staticmethod
    def get_all_books():
        """获取所有书籍信息"""
        return Book.query.order_by(Book.title).all()

    @staticmethod
    def get_book_by_id(book_id):
        """根据ID获取书籍详情"""
        return Book.query.get(book_id)

    @staticmethod
    def search_books(keyword):
        """搜索书籍（支持标题、作者、描述和ISBN）"""
        return Book.query.filter(
            (Book.title.ilike(f'%{keyword}%')) |
            (Book.author.ilike(f'%{keyword}%')) |
            (Book.description.ilike(f'%{keyword}%')) |
            (Book.isbn.ilike(f'%{keyword}%'))
        ).order_by(Book.title).all()

    @staticmethod
    def get_borrow_records(book_id):
        """获取指定书籍的所有借阅记录"""
        return (BorrowRecord.query
                .filter_by(book_id=book_id)
                .order_by(BorrowRecord.borrow_date.desc())
                .all())

    @staticmethod
    def get_reservations(book_id):
        """获取指定书籍的所有预约记录"""
        return (Reservation.query
                .filter_by(book_id=book_id)
                .order_by(Reservation.reservation_date.desc())
                .all())
    @staticmethod
    def get_popular_books(limit=5):
        """获取热门书籍（示例实现）"""
        # 实际项目应从数据库查询，这里使用模拟数据
        return [
            {"id": i, "title": f"热门书籍 {i}", "author": f"作者 {i}"}
            for i in range(1, limit+1)
        ]

    @staticmethod
    def get_book_status(book_id):
        """获取书籍当前状态"""
        book = Book.query.get(book_id)
        if not book:
            return 'not_found'
        return 'available' if book.available_copies > 0 else 'borrowed'

    @staticmethod
    def add_book(book_data):
        """添加新书到系统"""
        book = Book(
            title=book_data['title'],
            author=book_data['author'],
            description=book_data.get('description', ''),
            isbn=book_data.get('isbn'),
            publication_date=book_data.get('publication_date'),
            category=book_data.get('category'),
            available_copies=book_data.get('available_copies', 1),
            total_copies=book_data.get('total_copies', 1)
        )
        db.session.add(book)
        db.session.commit()
        return book

    @staticmethod
    def update_book(book_id, book_data):
        """更新书籍信息"""
        book = Book.query.get(book_id)
        if not book:
            return None

        # 更新可用副本数时确保不超过总副本数
        if 'available_copies' in book_data:
            total = book_data.get('total_copies', book.total_copies)
            book_data['available_copies'] = min(book_data['available_copies'], total)

        for key, value in book_data.items():
            if hasattr(book, key):
                setattr(book, key, value)

        db.session.commit()
        return book

    @staticmethod
    def borrow_book(book_id, user_id, borrow_days=14):
        """借阅书籍"""
        book = Book.query.get(book_id)
        user = User.query.get(user_id)

        if not book or not book.is_available():
            raise BookNotAvailableError('图书不可借阅')
        if not user:
            raise NotFoundError('用户不存在')

        borrow_date = datetime.utcnow()
        due_date = borrow_date + timedelta(days=borrow_days)

        borrow_record = BorrowRecord(
            book_id=book.id,
            user_id=user.id,
            borrow_date=borrow_date,
            due_date=due_date,
            status='borrowed'
        )

        book.available_copies -= 1
        if book.available_copies == 0:
            book.status = 'borrowed'

        db.session.add(borrow_record)
        db.session.commit()

        # 创建借阅成功通知
        notification = Notification(
            user_id=user.id,
            title='借阅成功',
            message=f'您已成功借阅《{book.title}》，应还日期：{due_date.strftime("%Y-%m-%d")}',
            type='borrow_success'
        )
        db.session.add(notification)
        db.session.commit()

        return borrow_record.id

    @staticmethod
    def get_borrowed_books(user_id=None):
        """获取借阅记录列表"""
        query = (BorrowRecord.query
                 .filter_by(status='borrowed')
                 .join(Book)
                 .join(User, BorrowRecord.user_id == User.id))

        if user_id is not None:
            query = query.filter(BorrowRecord.user_id == user_id)

        records = query.order_by(BorrowRecord.due_date.asc()).all()

        return [{
            'id': record.id,
            'book_id': record.book_id,
            'title': record.book.title,  # 改为 record.book
            'author': record.book.author,
            'cover_image': record.book.cover_image,
            'user_id': record.user_id,
            'username': record.borrower.username,  # 改为 record.borrower
            'borrow_date': record.borrow_date,
            'due_date': record.due_date,
            'status': record.status,
            'is_overdue': record.due_date < datetime.utcnow() if record.due_date else False
        } for record in records]

    @staticmethod
    def return_book(record_id, admin_id=None):
        """处理书籍归还（包含审批流程）"""
        # 首先获取借阅记录
        borrow_record = BorrowRecord.query.get(record_id)
        if not borrow_record:
            raise NotFoundError('借阅记录不存在')

        # 查找对应的归还请求
        return_request = ReturnRequest.query.filter_by(
            record_id=record_id,
            status='pending'
        ).first()

        # 更新借阅记录
        book = borrow_record.book
        borrow_record.status = 'returned'
        borrow_record.return_date = datetime.utcnow()
        book.available_copies += 1

        if book.available_copies > 0:
            book.status = 'available'

        # 如果有对应的归还请求，更新请求状态
        if return_request:
            return_request.status = 'approved'
            return_request.process_time = datetime.utcnow()
            if admin_id:
                return_request.admin_id = admin_id
                borrow_record.processed_by = admin_id

        db.session.commit()

        # 创建通知
        notification = Notification(
            user_id=borrow_record.user_id,
            title='归还成功',
            message=f'您已成功归还《{book.title}》',
            type='return_success'
        )
        db.session.add(notification)
        db.session.commit()

        return True

    @staticmethod
    def request_return(record_id, user_id):
        """提交归还申请（完整修正版）"""
        borrow_record = BorrowRecord.query.get_or_404(record_id)

        # 状态验证增强
        if borrow_record.status not in ['borrowed', 'overdue']:
            raise BookNotAvailableError("当前状态不可申请归还")

        # 关键修改：更新借阅记录状态
        borrow_record.status = 'returning'  # 必须设置这个状态
        borrow_record.updated_at = datetime.utcnow()

        # 创建归还申请记录
        return_request = ReturnRequest(
            record_id=record_id,
            user_id=user_id,
            status='pending',
            request_time=datetime.utcnow()
        )

        db.session.add(return_request)
        db.session.commit()  # 必须提交事务

        # 调试日志
        current_app.logger.debug(
            f"归还申请已创建，记录ID:{record_id}，新状态:{borrow_record.status}"
        )

        return return_request.id
    @staticmethod
    def get_return_requests(status='pending'):
        """获取还书申请列表"""
        return (ReturnRequest.query
                .filter_by(status=status)
                .join(BorrowRecord)
                .join(Book)
                .join(User, ReturnRequest.user_id == User.id)
                .order_by(ReturnRequest.request_time.asc())
                .all())

    @staticmethod
    def process_return_request(request_id, admin_id, approve, notes=None):
        """处理还书申请"""
        request = ReturnRequest.query.get(request_id)
        if not request:
            raise NotFoundError('申请记录不存在')
        if request.status != 'pending':
            raise BookNotAvailableError('该申请已处理')

        request.admin_id = admin_id
        request.process_time = datetime.utcnow()
        request.notes = notes

        if approve:
            # 批准还书
            BookService.return_book(request.record_id, admin_id)
            request.status = 'approved'

            # 给用户发送处理结果通知
            notification = Notification(
                user_id=request.user_id,
                title='还书申请已批准',
                message=f'您的还书申请已批准，《{request.borrow_record.book.title}》归还成功',
                type='request_processed'
            )
        else:
            # 拒绝还书
            request.status = 'rejected'

            # 给用户发送处理结果通知
            notification = Notification(
                user_id=request.user_id,
                title='还书申请被拒绝',
                message=f'您的还书申请被拒绝，原因：{notes or "未提供"}',
                type='request_processed'
            )

        db.session.add(notification)
        db.session.commit()
        return True

    @staticmethod
    def renew_book(record_id, renew_days=14):
        """续借书籍"""
        record = BorrowRecord.query.get(record_id)
        if not record:
            raise NotFoundError('借阅记录不存在')
        if record.status != 'borrowed':
            raise BookNotAvailableError('只能续借未归还的图书')
        if record.renew_count >= 2:  # 假设最多续借2次
            raise BookNotAvailableError('已达到最大续借次数')

        new_due_date = (record.due_date or datetime.utcnow()) + timedelta(days=renew_days)
        record.due_date = new_due_date
        record.renew_count += 1

        db.session.commit()

        # 发送续借成功通知
        notification = Notification(
            user_id=record.user_id,
            title='续借成功',
            message=f'您已成功续借《{record.book.title}》，新应还日期：{new_due_date.strftime("%Y-%m-%d")}',
            type='renew_success'
        )
        db.session.add(notification)
        db.session.commit()

        return new_due_date
